/**
 * by sunny 2015-12-08
 */
package uf.audit.util;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.jfinal.config.Routes;
import com.jfinal.kit.StrKit;
import org.apache.log4j.Logger;
import uf.audit.controller.UFBaseController;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

@SuppressWarnings({"rawtypes", "unchecked"})
public class AuditRoutes extends Routes {
    private static final Logger log = Logger.getLogger(AuditRoutes.class);
    private boolean autoScan = true;
    private String suffix = "Controller";
    private String packageName = ClassSearcher.DEFAULT_SCAN_CLASSPATH;
    private List<Class<?>> excludeClasses = Lists.newArrayList();
    private static Properties contollerDisabled = new Properties();
    private Class<?> scanBaseClass = UFBaseController.class;

    public Class<?> getScanBaseClass() {
        return scanBaseClass;
    }

    public void setScanBaseClass(Class<?> scanBaseClass) {
        this.scanBaseClass = scanBaseClass;
    }

    /**
     * taxconswitch.properties 这里面出现的类（全路径）不会被加入到routers里面
     */
    static {
        InputStream inStream = null;
        try {
            inStream = AuditRoutes.class.getResourceAsStream("/sysinfo.properties");
            if (inStream != null)
                contollerDisabled.load(inStream);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inStream != null)
                try {
                    inStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

    @Override
    public void config() {
        // TODO Auto-generated method stub
        final List<Class<?>> controllerClasses = new ArrayList<Class<?>>();
        ClassSearcher scan = new ClassSearcher();
        scan.addType(scanBaseClass);
        scan.setScanPaths(packageName);
        scan.scanClasses(new IScanInvoke() {

            public void invoke(ClassSearcher scan, Class clazz) {
                // TODO Auto-generated method stub
                controllerClasses.add(clazz);
                if (log.isDebugEnabled()) {
                    log.debug(clazz.getName() + " is loaded.");
                }
            }

        });
        Controller controllerAnnotation = null;
        for (Class controller : controllerClasses) {
            if (excludeClasses.contains(controller)) {
                continue;
            }
            String controllerName = controller.getName();
            boolean contollerDisabledValue = contollerDisabled.getProperty(controllerName) != null ? true : false;
            if (contollerDisabledValue) {
                log.info(controllerName + " skipped");
                continue;
            }
            controllerAnnotation = (Controller) controller.getAnnotation(Controller.class);
            if (controllerAnnotation == null) {
                // 不写注解默认类名去掉controller然后首字母小写
                if (!autoScan) {
                    continue;
                }
                this.add(controllerKey(controller), controller);
                log.debug("routes.add(" + controllerKey(controller) + ", " + controller.getName() + ")");
            } else if (StrKit.isBlank(controllerAnnotation.view())) {
                // 写了注解但是没有写view的路径，默认无视图的构造函数
                this.add(controllerAnnotation.url(), controller);
                log.debug("routes.add(" + controllerAnnotation.url() + ", " + controller.getName() + ")");
            } else {
                this.add(controllerAnnotation.url(), controller, controllerAnnotation.view());
                log.debug("routes.add(" + controllerAnnotation.url() + ", " + controller + ","
                        + controllerAnnotation.view() + ")");
            }
        }
    }

    public void scanPackage(String packageName) {
        this.packageName = packageName;
    }

    private String controllerKey(Class<Controller> clazz) {
        Preconditions.checkArgument(clazz.getSimpleName().endsWith(this.suffix),
                clazz.getName() + " is not annotated with @ControllerBind and not end with " + this.suffix);
        String controllerKey = "/" + StrKit.firstCharToLowerCase(clazz.getSimpleName());
        controllerKey = controllerKey.substring(0, controllerKey.indexOf(this.suffix));
        return controllerKey;
    }

    // 类似于 getter and setter

    public AuditRoutes autoScan(boolean autoScan) {
        this.autoScan = autoScan;
        return this;
    }

    public AuditRoutes addExcludeClasses(Class<? extends UFBaseController>[] clazzes) {
        if (clazzes != null) {
            for (Class clazz : clazzes) {
                this.excludeClasses.add(clazz);
            }
        }
        return this;
    }

    public AuditRoutes addExcludeClasses(List<Class<? extends UFBaseController>> clazzes) {
        this.excludeClasses.addAll(clazzes);
        return this;
    }

    public AuditRoutes suffix(String suffix) {
        this.suffix = suffix;
        return this;
    }

}
